;;; cl-synth : A software synthesiser for Common Lisp
;;; Copyright (C) 2010  Richard van Roy - (pluijzer [at] gmail [dot] com)

;;; This program is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published by
;;; the Free Software Foundation, either version 3 of the License, or
;;; (at your option) any later version.

;;; This program is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;; GNU General Public License for more details.

;;; You should have received a copy of the GNU General Public License
;;; along with this program.  If not, see <http://www.gnu.org/licenses/>

(in-package :cl-synth)

(defun repeat (object size)
  "Makes a list with object 'size' times in it."
  (loop for i from 1 to size collect object))

;;; TODO: biggest and smallest must be able to
;;;       work with more then two arguments.

(defmacro biggest (a b)
  "Returns the biggest list of two."
  `(if (> (length ,a) (length ,b)) ,a ,b))

(defmacro smallest (a b)
  "Returns the smallest list of two."
  `(if (< (length ,b) (length ,a)) ,b ,a))

(defun iota (count &optional (start 0) (step 1))
  "Makes a list from start to count of integers
increasing by steps."
  (loop repeat count for i from start by step collect i))

(defun value-type (value)
  "Returns if a value is a list or number."
  (if (numberp value) 'number
      (if (functionp value) 'function
	  (if (listp value) 'list
	      (error "Value not implemented!")))))

(defun to-single-float (n)
  "Convert any number to a simple-float"
  (coerce n 'single-float))

(defun intwine-aux (list1 list2 r)
  (if (not list1)
      r
      (intwine-aux (rest list1) (rest list2)
       (append r (list (first list1)) (list (first list2))))))

(defmacro intwine (&body args)
  "Intwine lists together."
  `(mapcan #'list ,@args))

(defun same?-aux (list p)
  (if (not list) t
      (if (= (first list) p)
	  (same?-aux (rest list) p)
	  nil)))

(defun same? (list)
  "Are all objects in a list the same?"
  (same?-aux (rest list) (first list)))

(defun same-length? (&rest lists)
  "Do all lists have the same length?"
  (same? (mapcar #'length lists)))

(defun extend (list size object)
  "Extend a list by size with object."
  (if (> (length list) size)
      list
      (append list (repeat object (- size (length list) )))))

(defmacro docollect (count &body body)
  "Do something 'count' times while collecting 'body'
in a list."
  `(let ((result nil))
     (dotimes (i ,count) 
       (push ,@body result))
     result))

(defmacro leval (s)
    `(loop for i in ',s collect
	  (loop for j in i collect (eval j))))

(defun smallest-pos-aux (list smallest pos count)
  (if (not list)
      pos
      (if (<= (first list) smallest)
	  (smallest-pos-aux (rest list) (first list) count (1+ count))
	  (smallest-pos-aux (rest list) smallest pos (1+ count)))))

(defun smallest-pos (list)
  (smallest-pos-aux list (first list) 0 0))

(defun nearest (list value)
  (smallest-pos (mapcar (lambda (x) (abs (- value x)))
			list)))

(defun positive? (value)
  (> value 0))

